/***************************************************************************
 *                                                                         *
 * Copyright (c) 2007 - 2009 Nuvoton Technology Corp. All rights reserved.*
 *                                                                         *
 ***************************************************************************/
 
/****************************************************************************
 * 
 * FILENAME
 *     NUC900_VPOST_TOPPOLY_TD035TTEA3.c
 *
 * VERSION
 *     0.1 
 *
 * DESCRIPTION
 *
 *
 *
 *
 * DATA STRUCTURES
 *     None
 *
 * FUNCTIONS
 *
 *
 *     
 * HISTORY
 *     2007.05.25		Created by Shih-Jen Lu
 *
 *
 * REMARK
 *     None
 *
 *
 **************************************************************************/
#ifdef ECOS
#include "stdio.h"
#include "stdlib.h"
#include "drv_api.h"
#include "wbio.h"
#else
#include "wblib.h"
#endif

#include "NUC900_VPOST_Regs.h"
#include "NUC900_VPOST.h"
#ifdef	HAVE_TOPPOLY_TD035TTEA3

//#define CHIP_950

#ifdef ECOS
cyg_handle_t	vpost_int_handle;
cyg_interrupt	vpost_int_holder;
#endif

static BOOL g_powerup=FALSE;
static UINT32 g_nScreenWidth;
static UINT32 g_nScreenHeight;

static void Delay(int nCnt)
{
	volatile int  loop;
	for (loop=0; loop<nCnt; loop++);
}

#if 1
static VOID vpostDisp_F_ISR(void)
{
    outpw(REG_LCM_INT_CS,inpw(REG_LCM_INT_CS) | VPOSTB_DISP_F_STATUS);
    vpostVAStartTrigger();
}
static VOID vpostUNDERRUN_ISR(void)
{
	outpw(REG_LCM_INT_CS,inpw(REG_LCM_INT_CS) | VPOSTB_UNDERRUN_INT);
}

static VOID vpostBUS_ERROR_ISR(void)
{
	outpw(REG_LCM_INT_CS,inpw(REG_LCM_INT_CS) | VPOSTB_BUS_ERROR_INT);
}
#ifdef ECOS
static cyg_uint32 vpostIntHandler(cyg_vector_t vector, cyg_addrword_t data)
#else
static VOID vpostIntHandler(void)
#endif
{
   /* clear VPOST interrupt state */
   UINT32 uintstatus;
   
   uintstatus = inpw(REG_LCM_INT_CS);
   if (uintstatus & VPOSTB_DISP_F_STATUS)  
      vpostDisp_F_ISR();
   else if (uintstatus & VPOSTB_UNDERRUN_INT)
      vpostUNDERRUN_ISR();
   else if (uintstatus & VPOSTB_BUS_ERROR_INT)
      vpostBUS_ERROR_ISR();

#ifdef ECOS
	return CYG_ISR_HANDLED;
#endif
}

static void vpostEnable_Int(void)
{
#ifdef ECOS
    cyg_interrupt_create(IRQ_LCD, 1, 0, vpostIntHandler, NULL, &vpost_int_handle, &vpost_int_holder);
    cyg_interrupt_attach(vpost_int_handle);
    cyg_interrupt_unmask(IRQ_LCD);
#else
    sysInstallISR(IRQ_LEVEL_1, IRQ_LCD, (PVOID)vpostIntHandler);
    /* enable VPOST interrupt */
    sysEnableInterrupt(IRQ_LCD);
#endif
    writew(REG_LCM_DCCS,readw(REG_LCM_DCCS) | VPOSTB_DISP_INT_EN);
    writew(REG_LCM_INT_CS,readw(REG_LCM_INT_CS) | VPOSTB_UNDERRUN_EN | VPOSTB_DISP_F_EN);
}
#endif

#ifdef CHIP_950

#define CS_HIGH  do { outpw(REG_GPIOE_DATAOUT, 1<<13); }while(0);
#define CS_LOW   do { outpw(REG_GPIOE_DATAOUT, inpw(REG_GPIOE_DATAOUT) & 0x1FFF); }while(0);
#define SCL_HIGH do { outpw(REG_GPIOG_DATAOUT, inpw(REG_GPIOG_DATAOUT) | 1<<2); }while(0);
#define SCL_LOW  do { outpw(REG_GPIOG_DATAOUT, inpw(REG_GPIOG_DATAOUT) & 0x1FFFB); }while(0);
#define SDA_HIGH do { outpw(REG_GPIOG_DATAOUT, inpw(REG_GPIOG_DATAOUT) | 1<<3); }while(0);
#define SDA_LOW  do { outpw(REG_GPIOG_DATAOUT, inpw(REG_GPIOG_DATAOUT) & 0x1FFF7); }while(0);

static void init_gpio(void)
{
 	//set share pin to GPIOG2, GPIOG3, GPIOE13
 	outpw(REG_MFSEL, inpw(REG_MFSEL) & 0xFFFCC7FF);
 
 	//set gpio dir
 	outpw(REG_GPIOG_DIR, 0xC);         // 950's gpioG [2,3]
	outpw(REG_GPIOE_DIR, 0x2000);   // 950's gpioE[13]
}

static void gpio_write_reg(unsigned char usRegIndex)
{
 int i;
 
 CS_HIGH
 CS_LOW
 
 SDA_LOW
 Delay(0x10);
 SCL_LOW
 Delay(0x50);
 SCL_HIGH
 Delay(0x50);
 SCL_LOW
 Delay(0x50);
 
 for(i=7;i>=0;i--)
 {
  if((usRegIndex >> i ) & 0x1)
   SDA_HIGH 
  else
   SDA_LOW
   
  Delay(0x10);  
  SCL_HIGH
  Delay(0x50);
  if(i!=0)
  {
   SCL_LOW
   Delay(0x50);
  }
 }
 
 CS_HIGH 
 SDA_LOW
 SCL_HIGH 
 Delay(0x50); 
}
static void gpio_write_reg_data(unsigned char usRegIndex, unsigned char usRegData)
{
 int i;
 
 CS_HIGH
 CS_LOW
 
 SDA_LOW
 Delay(0x10);
 SCL_LOW
 Delay(0x50);
 SCL_HIGH
 Delay(0x50);
 SCL_LOW
 Delay(0x50);
 
 for(i=7;i>=0;i--)
 {
  if((usRegIndex >> i ) & 0x1)
   SDA_HIGH 
  else
   SDA_LOW
  
  Delay(0x10);  
  SCL_HIGH
  Delay(0x50);
  SCL_LOW
  Delay(0x50);
 }
 
 SDA_HIGH
 Delay(0x10);
 SCL_HIGH
 Delay(0x50);
 SCL_LOW
 Delay(0x50);
 for(i=7;i>=0;i--)
 {
  if((usRegData >> i ) & 0x1)
   SDA_HIGH 
  else
   SDA_LOW
  
  Delay(0x10);  
  SCL_HIGH
  Delay(0x50); 
  if(i!=0)
  {
   SCL_LOW
   Delay(0x50);
  }
 }
 
 CS_HIGH 
 SDA_LOW
 SCL_HIGH 
 Delay(0x50); 
}
static void gpio_write_reg_data2(unsigned char usRegIndex, unsigned char usRegDataHB, unsigned char usRegDataLB)
{
 int i;
 
 CS_HIGH
 CS_LOW
 
 SDA_LOW
 Delay(0x10);
 SCL_LOW
 Delay(0x50);
 SCL_HIGH
 Delay(0x50);
 SCL_LOW
 Delay(0x50);
 
 for(i=7;i>=0;i--)
 {
  if((usRegIndex >> i ) & 0x1)
   SDA_HIGH 
  else
   SDA_LOW
   
  Delay(0x10);  
  SCL_HIGH
  Delay(0x50); 
  SCL_LOW
  Delay(0x50);
 }
 
 SDA_HIGH
 Delay(0x10);
 SCL_HIGH
 Delay(0x50);
 SCL_LOW
 Delay(0x50);
 for(i=7;i>=0;i--)
 {
  if((usRegDataHB >> i ) & 0x1)
   SDA_HIGH 
  else
   SDA_LOW
   
  Delay(0x10);  
  SCL_HIGH
  Delay(0x50); 
  SCL_LOW
  Delay(0x50);
 }
 
 SDA_HIGH
 Delay(0x10);
 SCL_HIGH
 Delay(0x50);
 SCL_LOW
 Delay(0x50);
 for(i=7;i>=0;i--)
 {
  if((usRegDataLB >> i ) & 0x1)
   SDA_HIGH 
  else
   SDA_LOW
   
  Delay(0x10);  
  SCL_HIGH
  Delay(0x50); 
  if(i!=0)
  {
   SCL_LOW
   Delay(0x50);
  }
 }
 
 CS_HIGH 
 SDA_LOW
 SCL_HIGH 
 Delay(0x50); 
} 

static GPIO_Setup_TOPPOLY_TD035TTEA3()
{
	outpw(REG_MFSEL, inpw(REG_MFSEL) & 0xFEFFFFF);
	outpw(GPIO_BA+0x54, 1<<2);
	outpw(GPIO_BA+0x58, 1<<2);
	init_gpio();
	
	gpio_write_reg_data(0xb0,0x02);//set DE mode
    	//gpio_write_reg_data2(0xb1,0x02, 0x10);//set DE mode
    	gpio_write_reg_data(0xb4,0x01);//display mode
    	gpio_write_reg_data(0x36,0x08);//Memory Access
    	gpio_write_reg_data(0xb7,0x03);
    	gpio_write_reg_data(0xbe,0x38);
    	gpio_write_reg_data(0xb5,0x19);
    	gpio_write_reg_data2(0xc0,0x08,0x08);//for panel timing setting
    	gpio_write_reg_data2(0xc2,0x18,0x18);//for panel timing setting
    	gpio_write_reg_data2(0xc4,0x30,0x30);//for panel timing setting
    	gpio_write_reg_data(0xc5,0x0c);//for panel timing setting
    	gpio_write_reg_data(0xed,0x04);//for panel timing setting
    	gpio_write_reg_data(0xba,0x45);//for gamma setting
    	gpio_write_reg_data2(0xd6,0x77,0x35);//for gamma setting
    	gpio_write_reg_data(0xd7,0x01);//for gamma setting
    	gpio_write_reg_data(0xd8,0x00);//for gamma setting
    	gpio_write_reg_data(0xd9,0x00);//for gamma setting
    	//sleep out
    	gpio_write_reg(0x11);
    	Delay(0x1000);//delay 6 frames
    
    	//display on
    	gpio_write_reg(0x29);
		
}

#else

static void InitUSI(UINT uBitCount)
{
    outpw(REG_CLKEN,inpw(REG_CLKEN) | (0x1<<29));
    outpw(REG_MFSEL,inpw(REG_MFSEL) &~(0xf<<14) | (0xa<<14));//GPIOG select USI interface
    /* initial NUC900 MicroWire */
    outpw(REG_USI_CNTRL, 0x00000006 | (uBitCount<<3));       // uBitCount bit(s) data per transmit, clock rising-edge latch data (falling change)
    outpw(REG_USI_DIVIDER, 49);             // Fsclk = Fpclk/(divider+1)*2. divided by 50
    outpw(REG_USI_SSR, 0x9);               // b4=1: automatic slave select; b3=0: select signal is active LOW
                                            // b0=1: SS0 enabled
}

static void USI_WriteRegOnly(UINT16 usRegIndex)
{   
    InitUSI(9);//9 bits per transfer
    while(inpw(REG_USI_CNTRL) & 0x01);                  // wait MicroWire interface is ready
    outpw(REG_USI_Tx0, (UINT32)usRegIndex);
    outpw(REG_USI_CNTRL, inpw(REG_USI_CNTRL) | 0x01);   // enable MW transfer
    while(inpw(REG_USI_CNTRL) & 0x01);                  // wait MicroWire interface is ready
}

static void USI_WriteRegData(UINT16 usRegIndex,UINT16 usRegData)
{   
    UINT32 uTransmitData;
    
    InitUSI(18);//18 bits per transfer
    uTransmitData = (UINT32)(usRegIndex<<9) | usRegData;
    while(inpw(REG_USI_CNTRL) & 0x01);                  // wait MicroWire interface is ready
    outpw(REG_USI_Tx0, uTransmitData);
    outpw(REG_USI_CNTRL, inpw(REG_USI_CNTRL) | 0x01);   // enable MW transfer
    while(inpw(REG_USI_CNTRL) & 0x01);                  // wait MicroWire interface is ready
}

static void USI_WriteReg2Data(UINT16 usRegIndex,UINT16 usRegDataHB,UINT16 usRegDataLB)
{   
    UINT32 uTransmitData;
    
    InitUSI(27);//27 bits per transfer
    uTransmitData = (UINT32)(usRegIndex<<18) | (UINT32)(usRegDataHB<<9) | usRegDataLB;
    while(inpw(REG_USI_CNTRL) & 0x01);                  // wait MicroWire interface is ready
    outpw(REG_USI_Tx0, uTransmitData);
    outpw(REG_USI_CNTRL, inpw(REG_USI_CNTRL) | 0x01);   // enable MW transfer
    while(inpw(REG_USI_CNTRL) & 0x01);                  // wait MicroWire interface is ready
}

static void Setup_TOPPOLY_TD035TTEA3(void)
{
    //Initial setting
    USI_WriteRegData(0x0b0,0x102);//set DE mode
    USI_WriteRegData(0x0b4,0x101);//display mode
    USI_WriteRegData(0x036,0x108);//Memory Access
    USI_WriteRegData(0x0b7,0x103);
    USI_WriteRegData(0x0be,0x138);
    USI_WriteRegData(0x0b5,0x119);
    USI_WriteReg2Data(0x0c0,0x108,0x108);//for panel timing setting
    USI_WriteReg2Data(0x0c2,0x118,0x118);//for panel timing setting
    USI_WriteReg2Data(0x0c4,0x130,0x130);//for panel timing setting
    USI_WriteRegData(0x0c5,0x10c);//for panel timing setting
    USI_WriteRegData(0x0ed,0x104);//for panel timing setting
    USI_WriteRegData(0x0ba,0x145);//for gamma setting
    USI_WriteReg2Data(0x0d6,0x177,0x135);//for gamma setting
    USI_WriteRegData(0x0d7,0x101);//for gamma setting
    USI_WriteRegData(0x0d8,0x100);//for gamma setting
    USI_WriteRegData(0x0d9,0x100);//for gamma setting
    
    //sleep out
    USI_WriteRegOnly(0x11);
    Delay(0x1000);//delay 6 frames
    
    //display on
    USI_WriteRegOnly(0x29);
    
}

#endif   /*  End of CHIP_950  */

INT vpostOSDInit_TOPPOLY_TD035TTEA3(POSDFORMATEX pOSDformatex)
{

    if ((pOSDformatex->nXstart > g_nScreenWidth) || (pOSDformatex->nYstart>g_nScreenHeight))
        return ERR_BAD_PARAMETER;

    vpostSetOSDSrc(pOSDformatex->ucOSDSrcFormat);
    
    vpostSetOSDBuffer(pOSDformatex->pFrameBuffer);
    /*if (ucOSDSrcType != 0)
     	writew(REG_LCM_DCCS,readw(REG_LCM_DCCS) | ucOSDSrcType);
     else
     	writew(REG_LCM_DCCS,readw(REG_LCM_DCCS) & 0xffff0fff);//clear OSD SRC setting	
	*/
	vpostOSDSetWindow(pOSDformatex->nXstart,pOSDformatex->nYstart,pOSDformatex->nOSDWidth,pOSDformatex->nOSDHeight);
     
	writew(REG_LCM_OSD_FBCTRL,0);//clear OSD STRIDE,FF setting
    if ((pOSDformatex->ucOSDSrcFormat==OSD_SRC_RGB888)||(pOSDformatex->ucOSDSrcFormat==OSD_SRC_RGB666))
    {
		writew(REG_LCM_OSD_FBCTRL,(pOSDformatex->nImageWidth<<16) | pOSDformatex->nImageWidth); //OSDFF~OSD_STRIDE
    }
    else if (pOSDformatex->ucOSDSrcFormat==OSD_SRC_RGB332)
    {
    	writew(REG_LCM_OSD_FBCTRL,((pOSDformatex->nImageWidth/4)<<16) | (pOSDformatex->nImageWidth/4)); //OSDFF~OSD_STRIDE
    }
    else{
        writew(REG_LCM_OSD_FBCTRL,((pOSDformatex->nImageWidth/2)<<16) | (pOSDformatex->nImageWidth/2)); //OSDFF~OSD_STRIDE
    }
    vpostOSDScalingCtrl(1,0,0);
    vpostOSDSetOverlay(DISPLAY_OSD,DISPLAY_OSD,0,0,0);
    return 0;
}



static VOID vpostSetCRTC_TOPPOLY_TD035TTEA3()
{   
	
	outpw(REG_LCM_CRTC_SIZE,0x010801B8); //CRTC_SIZE
    outpw(REG_LCM_CRTC_DEND,0x00F00140); //CRTC_DEND
    outpw(REG_LCM_CRTC_HR,0x01a00141); //CRTC_HR
    outpw(REG_LCM_CRTC_HSYNC,0x0191016b); //CRTC_HSYNC
    outpw(REG_LCM_CRTC_VR,0x010000f8); //CRTC_VR
    
	    

}


INT vpostLCMInit_TOPPOLY_TD035TTEA3(PLCDFORMATEX plcdformatex)
{
	UINT32 VA_FF;
	UINT32 VA_Sride;
	UINT32 nBytesPixel;
	
	if (g_powerup)
        return 0;
	
	outpw(REG_MFSEL,inpw(REG_MFSEL) | (3<<2));
	outpw(REG_CLKEN,inpw(REG_CLKEN) | 0x1);
	outpw(0xb0000220,0x1);//SW reset LCD
	
	outpw(REG_LCM_DCCS,inpw(REG_LCM_DCCS) | VPOSTB_ENG_RST);
	Delay(100);
	outpw(REG_LCM_DCCS,inpw(REG_LCM_DCCS) & ~VPOSTB_ENG_RST);
	Delay(100);
	
	
	g_nScreenWidth = plcdformatex->nScreenWidth = 320;
	g_nScreenHeight = plcdformatex->nScreenHeight = 240;
	
	if ( (plcdformatex->ucVASrcFormat == VA_SRC_RGB888) || (plcdformatex->ucVASrcFormat == VA_SRC_RGB666))//4 BytesPixel
	{
	    nBytesPixel = 4;
	}
	else
	{
	    nBytesPixel = 2;
	}
	plcdformatex->nFrameBufferSize = 240*320*nBytesPixel;
	
	
	/* set the display buffer (fetch from VA_BADDR0, if at single buffer mode)*/
	if (vpostAllocVABuffer(plcdformatex,nBytesPixel)==FALSE)
		return ERR_NULL_BUF;
	
	/* set display mode */
	vpostSetDisplayMode(0);//continue mode
	
	/* set display video source format */
	vpostSetVASrc(plcdformatex->ucVASrcFormat);
	/*
	if (ucVASrcType!=0)
		outpw(REG_LCM_DCCS,inpw(REG_LCM_DCCS) | ucVASrcType);
	else
		outpw(REG_LCM_DCCS,inpw(REG_LCM_DCCS) & ~(7<<8));
	*/
	//18-bit,256k,80mode,mpu-based,cmd18-16L0
	
	
	//vpostSetDeviceCtrl(_tTOPPOLY_TD035TTEA3);
	//outpw(REG_LCM_DEV_CTRL,0xA1C00004);
	//outpw(REG_LCM_DEV_CTRL,0x02E0000A);
	
	outpw(REG_LCM_DEV_CTRL,0x0);//clear register
	writew(REG_LCM_DEV_CTRL,inpw(REG_LCM_DEV_CTRL) | VPOSTB_DATA16or18
												   | VPOSTB_COLORTYPE_256K
												   | VPOSTB_DEVICE_SYNC_HIGHCOLOR
												   |(1<<19));
	
	

	vpostVAScalingCtrl(1,0,1,0,VA_SCALE_INTERPOLATION);
	vpostSetCRTC_TOPPOLY_TD035TTEA3();
	
	/* set video stream frame buffer control */
	VA_FF = (plcdformatex->nScreenWidth)*(nBytesPixel)/4;//word unit
    VA_Sride = (plcdformatex->nScreenWidth)*(nBytesPixel)/4;//word unit
    outpw(REG_LCM_VA_FBCTRL,inpw(REG_LCM_VA_FBCTRL) &~0x7ff07ff | (VA_FF<<16) | VA_Sride);
						
    vpostVAStartTrigger();
    
    #if CHIP_950
    	GPIO_Setup_TOPPOLY_TD035TTEA3();
    #else
    	Setup_TOPPOLY_TD035TTEA3();						
    #endif
    
	//vpostEnable_Int();
	
	if (!g_powerup)
        g_powerup=TRUE;
	return 0;
}

INT vpostLCMDeinit_TOPPOLY_TD035TTEA3()
{
    if (!g_powerup)
        return ERR_POWER_STATE;
    g_powerup = FALSE;
    vpostFreeVABuffer();
    vpostVAStopTrigger();
    return 0;
}

#endif	/* HAVE_TOPPOLY_TD035TTEA3 */
